<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <meta name="description" content="1、在INSTALLED_APPS中加入’rest_framework.authtoken’,INSTALLED_APPS = [    ‘’’    ‘rest_framework.authtoken’,  #    ‘’’]
2、配置jwt验证REST_FRAMEWORK = {    # 身份" />
  

  
  
  
  
  
  
  <title>jwt的使用 | 南辞的技术博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="1、在INSTALLED_APPS中加入’rest_framework.authtoken’,INSTALLED_APPS &#x3D; [    ‘’’    ‘rest_framework.authtoken’,  #    ‘’’] 2、配置jwt验证REST_FRAMEWORK &#x3D; {    # 身份认证    ‘DEFAULT_AUTHENTICATION_CLASSES’: (        ‘">
<meta property="og:type" content="article">
<meta property="og:title" content="jwt的使用">
<meta property="og:url" content="https://yanlidoushikeke.gitee.io/myhexo/2021/01/19/jwt%E7%9A%84%E4%BD%BF%E7%94%A8/index.html">
<meta property="og:site_name" content="南辞的技术博客">
<meta property="og:description" content="1、在INSTALLED_APPS中加入’rest_framework.authtoken’,INSTALLED_APPS &#x3D; [    ‘’’    ‘rest_framework.authtoken’,  #    ‘’’] 2、配置jwt验证REST_FRAMEWORK &#x3D; {    # 身份认证    ‘DEFAULT_AUTHENTICATION_CLASSES’: (        ‘">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2021-01-19T11:43:18.000Z">
<meta property="article:modified_time" content="2021-01-19T12:47:31.715Z">
<meta property="article:author" content="南辞">
<meta name="twitter:card" content="summary">
  
  
    <link rel="icon" href="/tefuir/css/images/favicon.ico">
  
  
<link rel="stylesheet" href="/tefuir/css/style.css">

  

  
  <!-- baidu webmaster push -->
  <script src='//push.zhanzhang.baidu.com/push.js'></script>
<meta name="generator" content="Hexo 5.2.0"><link rel="alternate" href="/tefuir/atom.xml" title="南辞的技术博客" type="application/atom+xml">
</head>
<body class="home blog custom-background custom-font-enabled single-author">
  <div id="page" class="hfeed site">
      <header id="masthead" class="site-header" role="banner">
    <hgroup>
      <h1 class="site-title">
        <a href="/tefuir/" title="南辞的技术博客" rel="home">南辞的技术博客</a>
      </h1>
      
        <h2 class="site-description hitokoto"></h2>
        <script type="text/javascript" src="https://v1.hitokoto.cn/?encode=js"></script>
      
    </hgroup>

    <nav id="site-navigation" class="main-navigation" role="navigation">
            <button class="menu-toggle">菜单</button>
            <a class="assistive-text" href="/#content" title="跳至内容">跳至内容</a><!--TODO-->
            <div class="menu-main-container">
                <ul id="menu-main" class="nav-menu">
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/tefuir/">Home</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/tefuir/archives">Archives</a></li>
                
                </ul>
            </div>
    </nav>
</header>

      <div id="main" class="wrapper">
        <div id="primary" class="site-content"><div id="content" role="main"><article id="post-jwt的使用" class="post-jwt的使用 post type-post status-publish format-standard hentry">
    <!---->

      <header class="entry-header">
        
        
  
    <h1 class="entry-title article-title">
      jwt的使用
    </h1>
  

        
        <div class="comments-link">
            
            <a href="javascript:void(0);" data-url="https://yanlidoushikeke.gitee.io/myhexo/2021/01/19/jwt%E7%9A%84%E4%BD%BF%E7%94%A8/" data-id="ckkttwp6r0003csu0eku5f1wh" class="leave-reply bdsharebuttonbox" data-cmd="more">Share</a>
        </div><!-- .comments-link -->
      </header><!-- .entry-header -->

    <div class="entry-content">
      
        <h2 id="1、在INSTALLED-APPS中加入’rest-framework-authtoken’"><a href="#1、在INSTALLED-APPS中加入’rest-framework-authtoken’" class="headerlink" title="1、在INSTALLED_APPS中加入’rest_framework.authtoken’,"></a>1、在INSTALLED_APPS中加入’rest_framework.authtoken’,</h2><p>INSTALLED_APPS = [<br>    ‘’’<br>    ‘rest_framework.authtoken’,  #<br>    ‘’’<br>]</p>
<h2 id="2、配置jwt验证"><a href="#2、配置jwt验证" class="headerlink" title="2、配置jwt验证"></a>2、配置jwt验证</h2><p>REST_FRAMEWORK = {<br>    # 身份认证<br>    ‘DEFAULT_AUTHENTICATION_CLASSES’: (<br>        ‘rest_framework_jwt.authentication.JSONWebTokenAuthentication’,<br>        ‘rest_framework.authentication.SessionAuthentication’,<br>        ‘rest_framework.authentication.BasicAuthentication’,<br>    ),<br>}</p>
<p>import datetime</p>
<p>JWT_AUTH = {<br>    ‘JWT_AUTH_HEADER_PREFIX’: ‘JWT’,<br>    ‘JWT_EXPIRATION_DELTA’: datetime.timedelta(days=1),<br>    ‘JWT_RESPONSE_PAYLOAD_HANDLER’:<br>        ‘users.views.jwt_response_payload_handler’,  # 重新login登录返回函数<br>}<br>AUTH_USER_MODEL=’users.User’  # 指定使用users APP中的 model User进行验证<br>settings.py 配置使用JWT</p>
<p>from django.contrib import admin<br>from django.urls import path,re_path,include</p>
<p>urlpatterns = [<br>    path(‘admin/‘, admin.site.urls),<br>    re_path(r’users/‘,include((‘users.urls’,’users’),namespace=’users’))<br>]</p>
<p>urls.py</p>
<p>from django.urls import path,re_path,include<br>from users import views<br>from rest_framework_jwt.views import obtain_jwt_token  # 验证密码后返回token</p>
<p>urlpatterns = [<br>    path(‘v1/register/‘, views.RegisterView.as_view(), name=’register’),  # 注册用户<br>    path(‘v1/login/‘, obtain_jwt_token,name=’login’),  # 用户登录后返回token<br>    path(‘v1/list/‘, views.UserList.as_view(), name=’register’),  # 测试需要携带token才能访问<br>]</p>
<p>users/urls.py</p>
<p>from django.db import models<br>from django.contrib.auth.models import AbstractUser</p>
<p>class User(AbstractUser):<br>    username = models.CharField(max_length=64, unique=True)<br>    password = models.CharField(max_length=255)<br>    phone = models.CharField(max_length=64)<br>    token = models.CharField(max_length=255)</p>
<h2 id="serializers-py"><a href="#serializers-py" class="headerlink" title="serializers.py"></a>serializers.py</h2><p>from rest_framework_jwt.settings import api_settings<br>from rest_framework import serializers<br>from users.models import User</p>
<p>class UserSerializer(serializers.Serializer):<br>    username = serializers.CharField()<br>    password = serializers.CharField()<br>    phone = serializers.CharField()<br>    token = serializers.CharField(read_only=True)</p>
<pre><code>def create(self, data):
    user = User.objects.create(**data)
    user.set_password(data.get(&#39;password&#39;))
    user.save()
    # 补充生成记录登录状态的token
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    payload = jwt_payload_handler(user)
    token = jwt_encode_handler(payload)
    user.token = token
    return user</code></pre>
<p>users/serializers.py 使用Serializer的create方法创建token</p>
<p>from django.shortcuts import render<br>import json<br>from rest_framework.views import APIView<br>from rest_framework.views import Response<br>from rest_framework.permissions import IsAuthenticated<br>from rest_framework_jwt.authentication import JSONWebTokenAuthentication<br>from users.serializers import UserSerializer</p>
<h3 id="用户注册"><a href="#用户注册" class="headerlink" title="用户注册"></a>用户注册</h3><p>class RegisterView(APIView):<br>    def post(self, request, *args, **kwargs):<br>        serializer = UserSerializer(data=request.data)<br>        if serializer.is_valid():<br>            serializer.save()<br>            return Response(serializer.data, status=201)<br>        return Response(serializer.errors, status=400)</p>
<h3 id="重新用户登录返回函数"><a href="#重新用户登录返回函数" class="headerlink" title="重新用户登录返回函数"></a>重新用户登录返回函数</h3><p>def jwt_response_payload_handler(token, user=None, request=None):<br>    ‘’’<br>    :param token: jwt生成的token值<br>    :param user: User对象<br>    :param request: 请求<br>    ‘’’<br>    return {<br>        ‘token’: token,<br>        ‘user’: user.username,<br>        ‘userid’: user.id<br>    }</p>
<h3 id="测试必须携带token才能访问接口"><a href="#测试必须携带token才能访问接口" class="headerlink" title="测试必须携带token才能访问接口"></a>测试必须携带token才能访问接口</h3><p>class UserList(APIView):<br>    permission_classes = [IsAuthenticated]  # 接口中加权限<br>    authentication_classes = [JSONWebTokenAuthentication]</p>
<pre><code>def get(self,request, *args, **kwargs):
    print(request.META.get(&#39;HTTP_AUTHORIZATION&#39;, None))
    return Response(&#123;&#39;name&#39;:&#39;zhangsan&#39;&#125;)
def post(self,request, *args, **kwargs):
    return Response(&#123;&#39;name&#39;:&#39;zhangsan&#39;&#125;)</code></pre>
<p>users/views.py</p>
<p>users/models.py 添加用户认证的User表</p>
<p>###1、指定允许的hosts，否则通过 <a target="_blank" rel="noopener" href="http://jack.com:8888/index/">http://jack.com:8888/index/</a> 无法访问jack_django程序<br>ALLOWED_HOSTS = [‘*’]</p>
<p>###2、将corsheaders 注册到app中<br>INSTALLED_APPS = [<br>    ‘django.contrib.admin’,<br>    ‘django.contrib.auth’,<br>    ‘django.contrib.contenttypes’,<br>    ‘django.contrib.sessions’,<br>    ‘django.contrib.messages’,<br>    ‘django.contrib.staticfiles’,<br>    ‘corsheaders’,<br>    ‘app01’,<br>]</p>
<p>###3、将下面两条添加到中间件重<br>MIDDLEWARE = [<br>    ‘corsheaders.middleware.CorsMiddleware’,<br>    ‘django.middleware.common.CommonMiddleware’,<br>]</p>
<p>###4、配置 django-cors-headers 中的参数<br>CORS_ALLOW_CREDENTIALS = True<br>CORS_ORIGIN_ALLOW_ALL = True</p>
<p>CORS_ORIGIN_WHITELIST = (</p>
<p>‘*’,</p>
<h6 id=""><a href="#" class="headerlink" title=")"></a>)</h6><p>CORS_ALLOW_METHODS = (<br>    ‘DELETE’,<br>    ‘GET’,<br>    ‘OPTIONS’,<br>    ‘PATCH’,<br>    ‘POST’,<br>    ‘PUT’,<br>    ‘VIEW’,<br>)</p>
<p>CORS_ALLOW_HEADERS = (<br>    ‘XMLHttpRequest’,<br>    ‘X_FILENAME’,<br>    ‘accept-encoding’,<br>    ‘authorization’,<br>    ‘content-type’,<br>    ‘dnt’,<br>    ‘origin’,<br>    ‘user-agent’,<br>    ‘x-csrftoken’,<br>    ‘x-requested-with’,<br>    ‘Pragma’,<br>)</p>
<p>settings.py 前后端分离配置cors</p>
<h3 id="通过用户token获取用户信息"><a href="#通过用户token获取用户信息" class="headerlink" title="通过用户token获取用户信息"></a>通过用户token获取用户信息</h3><p>from rest_framework_jwt.utils import jwt_decode_handler<br>toke_user = jwt_decode_handler(token)<br> {‘user_id’: 2, ‘username’: ‘lisi’, ‘exp’: 1561504444, ‘email’: ‘’}</p>
<p>1、cookie使用原理</p>
<p>　　　　　　1.用户向服务器发送用户名和密码。</p>
<p>　　　　　　2.验证服务器后，相关数据（如用户角色，登录时间等）将保存在当前会话中。</p>
<p>　　　　　　3.服务器向用户返回session_id，session信息都会写入到用户的Cookie。</p>
<p>　　　　　　4.用户的每个后续请求都将通过在Cookie中取出session_id传给服务器。</p>
<p>　　　　　　5.服务器收到session_id并对比之前保存的数据，确认用户的身份。</p>
<p>　　　　　　</p>
<p>　　2、session使用缺点</p>
<pre><code>  　　　　　　1. 这种模式最大的问题是，没有分布式架构，无法支持横向扩展。
  　　　　　　2. 如果使用一个服务器，该模式完全没有问题。
  　　　　　　3. 但是，如果它是服务器群集或面向服务的跨域体系结构的话，则需要一个统一的session数据库库来保存会话数据实现共享，
  　　　　　　4. 这样负载均衡下的每个服务器才可以正确的验证用户身份。</code></pre>
<p>　　3、常用解决session方法</p>
<pre><code>  　　　　　　1. 一种解决方案是通过持久化session数据，写入数据库或文件持久层等。
  　　　　　　2. 收到请求后，验证服务从持久层请求数据。
  　　　　　　3. 依赖于持久层的数据库或者问题系统，会有单点风险，如果持久层失败，整个认证体系都会挂掉。</code></pre>
<h2 id="1-2-JWT的介绍"><a href="#1-2-JWT的介绍" class="headerlink" title="1.2  JWT的介绍"></a>1.2  JWT的介绍</h2><h3 id="1、jwt-原则"><a href="#1、jwt-原则" class="headerlink" title="1、jwt 原则"></a>1、jwt 原则</h3><p>JWT的原则是在服务器身份验证之后，将生成一个JSON对象并将其发送回用户<br>{<br>“UserName”: “Chongchong”,<br>“Role”: “Admin”,<br>“Expire”: “2018-08-08 20:15:56”<br>}</p>
<p>之后，当用户与服务器通信时，客户在请求中发回JSON对象，服务器仅依赖于这个JSON对象来标识用户。<br>为了防止用户篡改数据，服务器将在生成对象时添加签名（有关详细信息，请参阅下文）。服务器不保存任何会话数据，即服务器变为无状态，使其更容易扩展</p>
<h3 id="2、JWT的数据结构"><a href="#2、JWT的数据结构" class="headerlink" title="2、JWT的数据结构"></a>2、JWT的数据结构</h3><p>　　　　　　1）jwt头：JWT头部分是一个描述JWT元数据的JSON对象</p>
<p>　　　　　　2）有效载荷：七个默认字段+自定义私有字段</p>
<p>　　　　　　3）签名=HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret)</p>
<p>　　　　　　</p>
<h3 id="JWT头"><a href="#JWT头" class="headerlink" title="JWT头"></a>JWT头</h3><p> JWT头部分是一个描述JWT元数据的JSON对象，通常如下所示。<br>{<br>“alg”: “HS256”,<br>“typ”: “JWT”<br>}<br> 1）alg属性表示签名使用的算法，默认为HMAC SHA256（写为HS256）；<br> 2）typ属性表示令牌的类型，JWT令牌统一写为JWT。<br>3）最后，使用Base64 URL算法将上述JSON对象转换为字符串保存。</p>
<h3 id="2）有效载荷"><a href="#2）有效载荷" class="headerlink" title="2）有效载荷"></a>2）有效载荷</h3><p>###1、有效载荷部分，是JWT的主体内容部分，也是一个JSON对象，包含需要传递的数据。 JWT指定七个默认字段供选择。<br>‘’’<br>iss：发行人<br>exp：到期时间<br>sub：主题<br>aud：用户<br>nbf：在此之前不可用<br>iat：发布时间<br>jti：JWT ID用于标识该JWT<br>‘’’</p>
<p>###2、除以上默认字段外，我们还可以自定义私有字段，如下例：<br>{<br>“sub”: “1234567890”,<br>“name”: “chongchong”,<br>“admin”: true<br>}</p>
<h3 id="3、注意"><a href="#3、注意" class="headerlink" title="3、注意"></a>3、注意</h3><p>默认情况下JWT是未加密的，任何人都可以解读其内容，因此不要构建隐私信息字段，存放保密信息，以防止信息泄露。<br>JSON对象也使用Base64 URL算法转换为字符串保存。</p>
<h3 id="有效载荷"><a href="#有效载荷" class="headerlink" title="有效载荷"></a>有效载荷</h3><h3 id="3）签名哈希"><a href="#3）签名哈希" class="headerlink" title="3）签名哈希"></a>3）签名哈希</h3><p>1.签名哈希部分是对上面两部分数据签名，通过指定的算法生成哈希，以确保数据不会被篡改。<br> 2.首先，需要指定一个密码（secret），该密码仅仅为保存在服务器中，并且不能向用户公开。<br> 3.然后，使用标头中指定的签名算法（默认情况下为HMAC SHA256）根据以下公式生成签名。<br> 4.HMACSHA256(base64UrlEncode(header) + “.” + base64UrlEncode(payload),secret)<br> 5.在计算出签名哈希后，JWT头，有效载荷和签名哈希的三个部分组合成一个字符串，每个部分用”.”分隔，就构成整个JWT对象。</p>
<h3 id="3、jwt核心"><a href="#3、jwt核心" class="headerlink" title="3、jwt核心"></a>3、jwt核心</h3><p>　　　　　　1）给用户颁发的token值相当于一把锁，服务器端的秘钥相当于一把钥匙</p>
<p>　　　　　　2）每次客户端请求都会携带这把锁，服务器端用秘钥去开这把锁，若果无法打开就证明是伪造的</p>
<h3 id="4、jwt特点分析"><a href="#4、jwt特点分析" class="headerlink" title="4、jwt特点分析"></a>4、jwt特点分析</h3><p>　　　　　　1、JWT默认不加密，但可以加密，生成原始令牌后，可以使用改令牌再次对其进行加密。</p>
<p>　　　　　　2、当JWT未加密方法是，一些私密数据无法通过JWT传输。</p>
<p>　　　　　　3、JWT不仅可用于认证，还可用于信息交换，善用JWT有助于减少服务器请求数据库的次数。</p>
<p>　　　　　　4、JWT的最大缺点是服务器不保存会话状态，所以在使用期间不可能取消令牌或更改令牌的权限，一旦JWT签发，在有效期内将会一直有效。</p>
<p>　　　　　　5、JWT本身包含认证信息，因此一旦信息泄露，任何人都可以获得令牌的所有权限。</p>
<p>　　　　　　6、为了减少盗用和窃取，JWT不建议使用HTTP协议来传输代码，而是使用加密的HTTPS协议进行传输。</p>

      
    </div><!-- .entry-content -->

    <footer class="entry-meta">
    <a href="/tefuir/2021/01/19/jwt%E7%9A%84%E4%BD%BF%E7%94%A8/">
    <time datetime="2021-01-19T11:43:18.000Z" class="entry-date">
        2021-01-19
    </time>
</a>
    
    
    </footer>
</article>


    
<nav class="nav-single">
    <h3 class="assistive-text">文章导航</h3>
    
        <span class="nav-previous"><a href="/tefuir/2021/01/19/hexo%E6%90%AD%E5%BB%BA%E4%B8%AA%E4%BA%BA%E7%BD%91%E7%AB%99/" rel="prev"><span class="meta-nav">←</span> hexo搭建个人网站</a></span>
    
    
        <span class="nav-next"><a href="/tefuir/2021/01/16/%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F/" rel="next">工厂模式 <span class="meta-nav">→</span></a></span>
    
</nav><!-- .nav-single -->







</div></div>
        <div id="secondary" class="widget-area" role="complementary">
  
    <aside id="search" class="widget widget_search"><form role="search" method="get" accept-charset="utf-8" id="searchform" class="searchform" action="//google.com/search">
    <div>
        <input type="text" value="" name="s" id="s" />
        <input type="submit" id="searchsubmit" value="搜索" />
    </div>
</form></aside>
  
    
  
    
  
    
  <aside class="widget">
    <h3 class="widget-title">Recents</h3>
    <div class="widget-content">
      <ul>
        
          <li>
            <a href="/tefuir/2021/04/26/python%E5%9F%BA%E7%A1%80%E7%90%86%E8%AE%BA%E5%AE%9D%E5%85%B8/">python基础理论宝典</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/python3-Flask%E7%BB%93%E5%90%88Socket-io%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0%E5%9C%A8%E7%BA%BF%E5%AE%A2%E6%9C%8D%E7%B3%BB%E7%BB%9F/">python3+Flask结合Socket.io简单实现在线客服系统</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/win10%E7%B3%BB%E7%BB%9F%E4%B8%8B%E5%88%A9%E7%94%A8docker%E9%83%A8%E7%BD%B2gunicorn-Flask%E6%89%93%E9%80%A0%E7%8B%AC%E7%AB%8B%E9%95%9C%E5%83%8F/">win10系统下利用docker部署gunicorn+Flask打造独立镜像</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/win10%E7%B3%BB%E7%BB%9F%E4%B8%8B%E5%9F%BA%E4%BA%8Edocker%E9%85%8D%E7%BD%AEelasticsearch%E9%85%8D%E5%90%88python3%E8%BF%9B%E8%A1%8C%E5%85%A8%E6%96%87%E6%A3%80%E7%B4%A2/">win10系统下基于docker配置elasticsearch配合python3进行全文检索</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%97%AE%E9%A2%98/">服务器问题</a>
          </li>
        
      </ul>
    </div>
  </aside>

  
    
  
    
  
</div>
      </div>
      <footer id="colophon" role="contentinfo">
    <p>&copy; 2021 南辞
    All rights reserved.</p>
    <p>Powered by <a href="http://hexo.io/" target="_blank">Hexo</a></p>
</footer>
    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"1","bdMiniList":false,"bdPic":"","bdStyle":"2","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='/js/share.js'];</script>

<script src="/js/jquery-3.3.1.min.js"></script>


  
<link rel="stylesheet" href="/tefuir/fancybox/jquery.fancybox.css">

  
<script src="/tefuir/fancybox/jquery.fancybox.pack.js"></script>




<script src="/tefuir/js/script.js"></script>


<script src="/js/navigation.js"></script>

<div id="bg"></div>

  </div>
</body>
</html>